home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmbase-grok-1.2 / evalfunc.c < prev    next >
C/C++ Source or Header  |  1995-06-25  |  13KB  |  605 lines

  1. /*
  2.  * all the functions that implement eval language features that require more
  3.  * than a line or two of code. All these functions are called from parser.y.
  4.  *
  5.  *    f_num
  6.  *    f_sum, f_qsum, f_ssum
  7.  *    f_avg, f_qavg, f_savg
  8.  *    f_dev, f_qdev, f_sdev
  9.  *    f_min, f_qmin, f_smin
  10.  *    f_max, f_qmax, f_smax
  11.  *    f_field
  12.  *    f_section
  13.  *    f_system
  14.  *    f_substr
  15.  *    f_instr
  16.  *    f_addarg
  17.  *    f_printf
  18.  */
  19.  
  20. #include "config.h"
  21. #include <X11/Xos.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <math.h>
  25. #include <Xm/Xm.h>
  26. #include "grok.h"
  27. #include "form.h"
  28. #include "proto.h"
  29. #include "y.tab.h"
  30.  
  31. extern CARD    *yycard;        /* the database to operate on */
  32. extern Widget    toplevel;        /* top-level shell for error msg */
  33.  
  34.  
  35. /*
  36.  * convert a string to a number. There is an internal version that doesn't
  37.  * free the string, and another version for the parser that does.
  38.  */
  39.  
  40. static double fnum(
  41.     char        *s)
  42. {
  43.     return(s ? atof(s) : 0);
  44. }
  45.  
  46. double f_num(
  47.     char        *s)
  48. {
  49.     double d = fnum(s);
  50.     if (s) free(s);
  51.     return(d);
  52. }
  53.  
  54.  
  55. /*
  56.  * All these functions run over the entire database and calculate something
  57.  * from a single column.
  58.  */
  59.  
  60. double f_sum(                /* sum */
  61.     register int    column)        /* number of column to average */
  62. {
  63.     register DBASE    *dbase = yycard->dbase;
  64.     register double    sum;
  65.     register int    row;
  66.  
  67.     if (!dbase || column < 0)
  68.         return(0);
  69.     for (sum=0, row=dbase->nrows-1; row >= 0; row--)
  70.         sum += fnum(dbase_get(dbase, row, column));
  71.     return(sum);
  72. }
  73.  
  74.  
  75. double f_avg(                /* average */
  76.     register int    column)        /* number of column to average */
  77. {
  78.     register double    sum = f_sum(column);
  79.     return(yycard->dbase->nrows ? sum / yycard->dbase->nrows : 0);
  80. }
  81.  
  82.  
  83. double f_dev(                /* standard deviation */
  84.     register int    column)        /* number of column to average */
  85. {
  86.     register DBASE    *dbase = yycard->dbase;
  87.     register double    sum, avg, val;
  88.     register int    row;
  89.  
  90.     if (!dbase || column < 0)
  91.         return(0);
  92.     avg = f_avg(column);
  93.     for (sum=0, row=dbase->nrows-1; row >= 0; row--) {
  94.         val = fnum(dbase_get(dbase, row, column)) - avg;
  95.         sum += val * val;
  96.     }
  97.     return(sqrt(sum / dbase->nrows));
  98. }
  99.  
  100.  
  101. double f_min(                /* minimum */
  102.     register int    column)        /* number of column to average */
  103. {
  104.     register DBASE    *dbase = yycard->dbase;
  105.     register double    min = 1e100, val;
  106.     register int    row;
  107.  
  108.     if (!dbase || column < 0)
  109.         return(0);
  110.     for (row=dbase->nrows-1; row >= 0; row--) {
  111.         val = fnum(dbase_get(dbase, row, column));
  112.         if (val < min)
  113.             min = val;
  114.     }
  115.     return(min == 1e100 ? 0 : min);
  116. }
  117.  
  118.  
  119. double f_max(                /* maximum */
  120.     register int    column)        /* number of column to average */
  121. {
  122.     register DBASE    *dbase = yycard->dbase;
  123.     register double    max = -1e100, val;
  124.     register int    row;
  125.  
  126.     if (!dbase || column < 0)
  127.         return(0);
  128.     for (row=dbase->nrows-1; row >= 0; row--) {
  129.         val = fnum(dbase_get(dbase, row, column));
  130.         if (val > max)
  131.             max = val;
  132.     }
  133.     return(max == -1e100 ? 0 : max);
  134. }
  135.  
  136.  
  137. /*
  138.  * All these functions run over a query or the entire database and calculate
  139.  * something from a single column.
  140.  */
  141.  
  142. double f_qsum(                /* sum */
  143.     register int    column)        /* number of column to average */
  144. {
  145.     register DBASE    *dbase = yycard->dbase;
  146.     register double    sum = 0;
  147.     register int    row;
  148.  
  149.     if (!dbase || column < 0)
  150.         return(0);
  151.     if (!yycard->query)
  152.         return(f_sum(column));
  153.     for (row=0; row < yycard->nquery; row++)
  154.         sum += fnum(dbase_get(dbase, yycard->query[row], column));
  155.     return(sum);
  156. }
  157.  
  158.  
  159. double f_qavg(                /* average */
  160.     register int    column)        /* number of column to average */
  161. {
  162.     register double    sum = f_qsum(column);
  163.     register int    count;
  164.  
  165.     count = yycard->query ? yycard->nquery : yycard->dbase->nrows;
  166.     return(count ? sum / count : 0);
  167. }
  168.  
  169.  
  170. double f_qdev(                /* standard deviation */
  171.     register int    column)        /* number of column to average */
  172. {
  173.     register DBASE    *dbase = yycard->dbase;
  174.     register double    sum = 0, avg, val;
  175.     register int    row;
  176.  
  177.     if (!dbase || column < 0)
  178.         return(0);
  179.     if (!yycard->query)
  180.         return(f_dev(column));
  181.     if (!yycard->nquery)
  182.         return(0);
  183.     avg = f_qavg(column);
  184.     for (row=0; row < yycard->nquery; row++) {
  185.         val = fnum(dbase_get(dbase, yycard->query[row], column)) - avg;
  186.         sum += val * val;
  187.     }
  188.     return(sqrt(sum / yycard->nquery));
  189. }
  190.  
  191.  
  192. double f_qmin(                /* minimum */
  193.     register int    column)        /* number of column to average */
  194. {
  195.     register DBASE    *dbase = yycard->dbase;
  196.     register double    min = 1e100, val;
  197.     register int    row;
  198.  
  199.     if (!dbase || column < 0)
  200.         return(0);
  201.     if (!yycard->query)
  202.         return(f_min(column));
  203.     for (row=0; row < yycard->nquery; row++) {
  204.         val = fnum(dbase_get(dbase, yycard->query[row], column));
  205.         if (val < min)
  206.             min = val;
  207.     }
  208.     return(min == 1e100 ? 0 : min);
  209. }
  210.  
  211.  
  212. double f_qmax(                /* maximum */
  213.     register int    column)        /* number of column to average */
  214. {
  215.     register DBASE    *dbase = yycard->dbase;
  216.     register double    max = -1e100, val;
  217.     register int    row;
  218.  
  219.     if (!dbase || column < 0)
  220.         return(0);
  221.     if (!yycard->query)
  222.         return(f_max(column));
  223.     for (row=0; row < yycard->nquery; row++) {
  224.         val = fnum(dbase_get(dbase, yycard->query[row], column));
  225.         if (val > max)
  226.             max = val;
  227.     }
  228.     return(max == -1e100 ? 0 : max);
  229. }
  230.  
  231.  
  232. /*
  233.  * All these functions run over the entire database and calculate something
  234.  * from a single section.
  235.  */
  236.  
  237. double f_ssum(                /* sum */
  238.     register int    column)        /* number of column to average */
  239. {
  240.     register DBASE    *dbase = yycard->dbase;
  241.     register int    sect;
  242.     register double    sum;
  243.     register int    row;
  244.  
  245.     if (!dbase || column < 0)
  246.         return(0);
  247.     if ((sect = dbase->currsect) < 0)
  248.         return(f_sum(column));
  249.     for (sum=0, row=dbase->nrows-1; row >= 0; row--)
  250.         if (dbase->row[row]->section == sect)
  251.             sum += fnum(dbase_get(dbase, row, column));
  252.     return(sum);
  253. }
  254.  
  255.  
  256. double f_savg(                /* average */
  257.     register int    column)        /* number of column to average */
  258. {
  259.     register DBASE    *dbase = yycard->dbase;
  260.     register int    sect;
  261.     register double    sum;
  262.     register int    row, num=0;
  263.  
  264.     if (!dbase || column < 0)
  265.         return(0);
  266.     if ((sect = dbase->currsect) < 0)
  267.         return(f_avg(column));
  268.     for (sum=0, row=dbase->nrows-1; row >= 0; row--)
  269.         if (dbase->row[row]->section == sect) {
  270.             sum += fnum(dbase_get(dbase, row, column));
  271.             num++;
  272.         }
  273.     return(num ? sum / sum : 0);
  274. }
  275.  
  276.  
  277. double f_sdev(                /* standard deviation */
  278.     register int    column)        /* number of column to average */
  279. {
  280.     register DBASE    *dbase = yycard->dbase;
  281.     register int    sect;
  282.     register double    sum, avg, val;
  283.     register int    row, num=0;
  284.  
  285.     if (!dbase || column < 0)
  286.         return(0);
  287.     if ((sect = dbase->currsect) < 0)
  288.         return(f_dev(column));
  289.     avg = f_savg(column);
  290.     for (sum=0, row=dbase->nrows-1; row >= 0; row--)
  291.         if (dbase->row[row]->section == sect) {
  292.             val = fnum(dbase_get(dbase, row, column)) - avg;
  293.             sum += val * val;
  294.             num++;
  295.         }
  296.     return(num ? sqrt(sum / num) : 0);
  297. }
  298.  
  299.  
  300. double f_smin(                /* minimum */
  301.     register int    column)        /* number of column to average */
  302. {
  303.     register DBASE    *dbase = yycard->dbase;
  304.     register int    sect;
  305.     register double    min = 1e100, val;
  306.     register int    row;
  307.  
  308.     if (!dbase || column < 0)
  309.         return(0);
  310.     if ((sect = dbase->currsect) < 0)
  311.         return(f_min(column));
  312.     for (row=dbase->nrows-1; row >= 0; row--)
  313.         if (dbase->row[row]->section == sect) {
  314.             val = fnum(dbase_get(dbase, row, column));
  315.             if (val < min)
  316.                 min = val;
  317.         }
  318.     return(min == 1e100 ? 0 : min);
  319. }
  320.  
  321.  
  322. double f_smax(                /* maximum */
  323.     register int    column)        /* number of column to average */
  324. {
  325.     register DBASE    *dbase = yycard->dbase;
  326.     register int    sect;
  327.     register double    max = -1e100, val;
  328.     register int    row;
  329.  
  330.     if (!dbase || column < 0)
  331.         return(0);
  332.     if ((sect = dbase->currsect) < 0)
  333.         return(f_max(column));
  334.     for (row=dbase->nrows-1; row >= 0; row--)
  335.         if (dbase->row[row]->section == sect) {
  336.             val = fnum(dbase_get(dbase, row, column));
  337.             if (val > max)
  338.                 max = val;
  339.         }
  340.     return(max == -1e100 ? 0 : max);
  341. }
  342.  
  343.  
  344. /*
  345.  * return the value of a database field
  346.  */
  347.  
  348. char *f_field(
  349.     int        column,
  350.     int        row)
  351. {
  352.     return(mystrdup(dbase_get(yycard->dbase, row, column)));
  353. }
  354.  
  355.  
  356. /*
  357.  * return the section of a card in the database
  358.  */
  359.  
  360. int f_section(
  361.     int        nrow)
  362. {
  363.     register ROW    *row;        /* row to get from */
  364.  
  365.     if (yycard && yycard->dbase
  366.            && nrow >= 0
  367.            && nrow < yycard->dbase->nrows
  368.            && (row = yycard->dbase->row[nrow]))
  369.         return(row->section);
  370.     return(0);
  371. }
  372.  
  373.  
  374. /*
  375.  * run a system command, and return stdout of the command (backquotes)
  376.  */
  377.  
  378. char *f_system(
  379.     char        *cmd)
  380. {
  381.     char        outpath[80];
  382.     char        errpath[80];
  383.     int        fd0_save = dup(0);
  384.     int        fd1_save = dup(1);
  385.     int        fd2_save = dup(2);
  386.     FILE        *fp;
  387.     char        data[32768];
  388.     int        size, i;
  389.  
  390.     if (!cmd || !*cmd)
  391.         return(0);
  392.     close(1);                    /* run cmd */
  393.     sprintf(outpath, "/tmp/grok%05dout", getpid());
  394.     (void)open(outpath, O_WRONLY | O_CREAT, 0600);
  395.     close(2);
  396.     sprintf(errpath, "/tmp/grok%05derr", getpid());
  397.     (void)open(errpath, O_WRONLY | O_CREAT, 0600);
  398.     close(0);
  399.     (void)open("/dev/null", O_RDONLY);
  400.     (void)system(cmd);
  401.     dup2(fd0_save, 0);    /*<<< arg order? */
  402.     dup2(fd1_save, 1);
  403.     dup2(fd2_save, 2);
  404.                             /* error messages */
  405.     if (fp = fopen(errpath, "r")) {
  406.         (void)fseek(fp, 0, 2);
  407.         if (size = ftell(fp)) {
  408.             rewind(fp);
  409.             sprintf(data, "Command failed: %s\n", cmd);
  410.             i = strlen(data);
  411.             if (i + size > sizeof(data)-1)
  412.                 size = sizeof(data)-1 - i;
  413.             size = fread(data+i, 1, size, fp);
  414.             data[i + size] = 0;
  415.             create_error_popup(toplevel, 0, data);
  416.         }
  417.         fclose(fp);
  418.     }
  419.                             /* result */
  420.     *data = 0;
  421.     if (fp = fopen(outpath, "r")) {
  422.         (void)fseek(fp, 0, 2);
  423.         if (size = ftell(fp)) {
  424.             rewind(fp);
  425.             if (size > sizeof(data)-1)
  426.                 size = sizeof(data)-1;
  427.             size = fread(data, 1, size, fp);
  428.             data[size] = 0;
  429.         }
  430.         fclose(fp);
  431.     }
  432.     unlink(outpath);
  433.     unlink(errpath);
  434.     free((void *)cmd);
  435.     return(*data ? mystrdup(data) : 0);
  436. }
  437.  
  438.  
  439. /*
  440.  * cut num chars at pos from string
  441.  */
  442.  
  443. char *f_substr(
  444.     char        *string,
  445.     int        pos,
  446.     int        num)
  447. {
  448.     int        len;
  449.     char        *new = 0;
  450.  
  451.     if (!string)
  452.         return(0);
  453.     len = strlen(string);
  454.     if (pos < 0)
  455.         pos = len + pos;
  456.     if (pos < 0)
  457.         pos = 0;
  458.     if (pos < len) {
  459.         if (num > len - pos)
  460.             num = len - pos;
  461.         if (num > 0 && (new = malloc(num + 1))) {
  462.             strncpy(new, string+pos, num);
  463.             new[num] = 0;
  464.         }
  465.     }
  466.     free((void *)string);
  467.     return(new);
  468. }
  469.  
  470.  
  471. /*
  472.  * return true if <match> is contained in <string>
  473.  */
  474.  
  475. BOOL f_instr(
  476.     register char    *match,
  477.     register char    *string)
  478. {
  479.     register int    i;
  480.  
  481.     if (!match || !*match) {
  482.         if (match)
  483.             free((void *)match);
  484.         if (string)
  485.             free((void *)string);
  486.         return(TRUE);
  487.     }
  488.     if (!string) {
  489.         free((void *)match);
  490.         return(FALSE);
  491.     }
  492.     for (; *string; string++)
  493.         for (i=0; ; i++) {
  494.             if (!match[i]) {
  495.                 free((void *)match);
  496.                 free((void *)string);
  497.                 return(TRUE);
  498.             }
  499.             if (match[i] != string[i])
  500.                 break;
  501.         }
  502.     free((void *)match);
  503.     free((void *)string);
  504.     return(FALSE);
  505. }
  506.  
  507.  
  508. /*
  509.  * compose an argument list, by adding a new string argument to an existing
  510.  * list of string arguments. The result is used and freed by f_printf().
  511.  */
  512.  
  513. struct arg *f_addarg(
  514.     struct arg    *list,        /* easier to keep struct arg local */
  515.     char        *value)        /* argument to append to list */
  516. {
  517.     struct arg    *new = (struct arg *)malloc(sizeof(struct arg));
  518.     struct arg    *tail;
  519.  
  520.     for (tail=list; tail && tail->next; tail=tail->next);
  521.     if (tail)
  522.         tail->next = new;
  523.     if (new) {
  524.         new->next  = 0;
  525.         new->value = value;
  526.     }
  527.     return(list ? list : new);
  528. }
  529.  
  530.  
  531. /*
  532.  * sprintf to allocated memory, and return a pointer to the resulting string.
  533.  * Requires an argument list, which is freed when finished. What makes this a
  534.  * bit difficult is that sprintf expects different arg data types for different
  535.  * % controls. Only the final % control char is used for determining the type,
  536.  * the actual printing is still done by printf. This will blow up if someone
  537.  * says "%100000s".
  538.  */
  539.  
  540. char *f_printf(
  541.     struct arg    *arg)
  542. {
  543.     struct arg    *argp;        /* next argument */
  544.     char        *value;        /* value string from next argument */
  545.     char        buf[10240];    /* result buffer */
  546.     char        *bp = buf;    /* next free char in result buffer */
  547.     char        *fmt;        /* next char from format string */
  548.     char        *ctl;        /* for scanning % controls */
  549.     char        cbuf[100];    /* control substring, [0] is '%' */
  550.     int        i;
  551.  
  552.     if (!arg || !*arg->value)
  553.         return(0);
  554.     argp = arg->next;
  555.     fmt  = arg->value;
  556.     while (*fmt) {
  557.         if (*fmt == '\\' && fmt[1]) {
  558.             fmt++;
  559.             *bp++ = *fmt++;
  560.         } else if (*fmt != '%') {
  561.             *bp++ = *fmt++;
  562.         } else {
  563.             for (ctl=fmt+1; strrchr("0123456789.-", *ctl); ctl++);
  564.             if (*ctl == 'l')
  565.                 ctl++;
  566.             i = ctl - fmt + 1;
  567.             if (i > sizeof(cbuf)-1)
  568.                 i = sizeof(cbuf)-1;
  569.             strncpy(cbuf, fmt, i);
  570.             cbuf[i] = 0;
  571.             value = argp && argp->value ? argp->value : "";
  572.             switch(*ctl) {
  573.               case 'c':
  574.               case 'd':
  575.               case 'x':
  576.               case 'X':
  577.               case 'o':
  578.               case 'i':
  579.               case 'u':
  580.                 sprintf(bp, cbuf, atoi(value));
  581.                 break;
  582.               case 'e':
  583.               case 'E':
  584.               case 'f':
  585.               case 'F':
  586.               case 'g':
  587.               case 'G':
  588.                 sprintf(bp, cbuf, atof(value));
  589.                 break;
  590.               case 's':
  591.                 sprintf(bp, cbuf, value);
  592.                 break;
  593.               default:
  594.                 strcat(bp, cbuf);
  595.             }
  596.             if (argp)
  597.                 argp = argp->next;
  598.             bp += strlen(bp);
  599.             fmt = ctl+1;
  600.         }
  601.     }
  602.     *bp = 0;
  603.     return(mystrdup(buf));
  604. }
  605.